/*! \file ReaderStatusProc.h
    \brief Une implementation d'un dumper permettant d'extraire les 
    informations sur l'etat d'un processus.    
*/
#ifndef __ReaderStatusProc__
#define __ReaderStatusProc__

#include <unistd.h>
#include <cassert>
#include <string>
#include <fstream>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <cstring>
using namespace std;

#define PROC "/proc/"
#define VmSize "VmSize"
#define VmPeak "VmPeak" 
#define VmStk  "VmStk"
#define VmLib  "VmLib"
#define VmExe  "VmExe"
#define VmData "VmData"
#define VmRSS  "VmRSS"
#define VmHWM  "VmHWM"



/**
 *\brief structure de donnees stockant les informations issues du noyau
 * concernant un processus.
 */   
typedef struct
{
  /**
   * taille en memoire virtuelle du processus.
   */
  size_t vmSize;
  
  /**
   * pick en memoire virtuelle.
   */
  size_t vmPeak;
  
  /**
   * taille de la pile en memoire virtuelle.
   */	
  size_t vmStk;
  
  /**
   * taille du code des bibliotheques dynamiques.
   */
  size_t vmLib;
  
  /**
   * taille du segment de code du processus appelant.
   */
  size_t vmExe;

  /**
   *taille du segment de donnees du processus appelant.
   */
  size_t vmData;

  /**
   *taille de la memoire residente du processus appelant.
   */
  size_t vmRSS;
  
  /**
   *peak en memoire residente.
   */
  size_t vmHWM;

  /**
   *pid du processus appelant.
   */
  pid_t Pid;
  string ProcFile;
  /**
   * nom de l'executable
   */
  char name[1024];
} status_t;



static void  getSizeFromString( char const * const  endLine, size_t & size  )
{
  int n=0;
  n=sscanf( endLine , "%li", (unsigned int*) &size );
  assert( n!=EOF && n!=0 );	
} 

static void  readStatus(status_t & status)
{
  std::string line;
  int k=0;
  std::ifstream statusFile(status.ProcFile.c_str(), std::ios::in);
  
  if(statusFile)
    {
      k=0;
      while ( getline(statusFile, line) && (k<10) ){
	if ( strncmp( line.c_str(), "VmSize:", 7 ) == 0 ){
	  getSizeFromString( line.c_str()+7, status.vmSize );
	  ++k;
	}				
	else if ( strncmp( line.c_str(), "VmPeak:", 7 ) == 0 ){
	  getSizeFromString( line.c_str()+7,status.vmPeak );
	  ++k;
	}
	else if ( strncmp( line.c_str(), "VmStk:", 6 ) == 0 ){
	  getSizeFromString( line.c_str()+6,status.vmStk );
	  ++k;
	}
	else if ( strncmp( line.c_str(), "VmLib:", 6 ) == 0 ){
	  getSizeFromString( line.c_str()+6,status.vmLib );
	  ++k;
	}
	else if ( strncmp( line.c_str(), "VmExe:", 6 ) == 0 ){
	      getSizeFromString( line.c_str()+6,status.vmExe );
	      ++k;
	    }
	else if ( strncmp( line.c_str(), "VmData:", 7 ) == 0 ){
	  getSizeFromString( line.c_str()+7,status.vmData );
	  ++k;
	}
	else if ( strncmp( line.c_str(), "VmRSS:", 6 ) == 0 ){
	  getSizeFromString( line.c_str()+6,status.vmRSS );
	  ++k;
	}
	else if ( strncmp( line.c_str(), "VmHWM:", 6 ) == 0 ){
	  getSizeFromString( line.c_str()+6,status.vmHWM );
	  ++k;
	}
        else if ( strncmp( line.c_str(), "Name:", 5 ) == 0 ){
            strncpy(status.name,line.c_str(),strlen(line.c_str())+1);
	}
        
      }
    }
  statusFile.close();
}


#define UNITE 1024 //(MB)
/**
 *\brief Permet de dumper les informations status issues du noyau.
 *\class DumperStatusProc 
 */
class ReaderStatusProc
{ 
    
 private:
 static status_t status;
 
public:
  /**
   *\brief retourne une structure decrivant le status du processus profile.
   *\seeAlso status_t
   */
  static void getStatus(pid_t pid,status_t &st){
    stringstream proc_file (stringstream::in | stringstream::out);
    proc_file.flush();
    proc_file << PROC << pid <<"/status";
    st.ProcFile=proc_file.str();
    readStatus(st);
  }
  
  /**
   * \brief 
   * @param st
   */
  static void getSelfStatus(status_t &st) {
      stringstream proc_file (stringstream::in | stringstream::out);
      proc_file.flush();
      st.Pid=getpid();
      proc_file << PROC << st.Pid <<"/status";
      st.ProcFile=proc_file.str();
      readStatus(st);
  }
 
  
  /**
   * \brief
   * @param st
   */
  static void printStatus(status_t &st,const char* bin,long unit,const char*u){
      
      printf("\033[34;1mVmSize :%s\033[m = %d\n",u,st.vmSize  /  (size_t)unit);
      printf("\033[34;1mVmRSS  :%s\033[m = %d\n",u,st.vmRSS   /  (size_t)unit);
      printf("\033[34;1mVmPeak :%s\033[m = %d\n",u,st.vmPeak /  (size_t)unit);
      printf("\033[34;1mVmHWM  :%s\033[m = %d\n",u,st.vmHWM   /  (size_t)unit);
      
      printf("\033[34;1mVmData :%s\033[m = %d\n",u,st.vmData  /  (size_t)unit);
      printf("\033[34;1mVmStk  :%s\033[m = %d\n",u,st.vmStk   /  (size_t)unit);
      printf("\033[34;1mVmExe  :%s\033[m = %d\n",u,st.vmExe   /  (size_t)unit);
      printf("\033[34;1mVmLib  :%s\033[m = %d\n",u,st.vmLib   /  (size_t)unit);
        
  }
};



#endif
